// 定义向量类
class Vector{
  constructor([x, y]) {
    this.x = x
    this.y = y
  }
  // 获取向量的模
  getModule() {
    return Number(Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)).toFixed(2))
  }
  // 1、两个向量相减，得到边向量
  substruct(vector) {
    const v = new Vector([0, 0])
    v.x = this.x - vector.x
    v.y = this.y - vector.y
    return v
  }
  // 2、通过边向量获取法向量，通过这个法向量就可以计算其他向量在法向量上的投影长度
  getNormalVector() {
    const v = new Vector([0, 0])
    v.x = 0 + this.y
    v.y = 0 - this.x
    return v
  }
  // 3、通过计算获取单位法向量, 法向量的单位向量获取函数
  getUnitVector() {
    const v = new Vector([0, 0])
    const m = this.getModule()
    if (m !== 0) {
      v.x = Number((this.x / m).toFixed(2))
      v.y = Number((this.y / m).toFixed(2))
    }
    return v
  }
  // 4、计算投影长度
  getShadowLength(vector) {
    return Number((this.x * vector.x + this.y * vector.y).toFixed(2))
  }
  // 获取单位法向量
  getUnitNormalVector() {
    const v = this.getNormalVector()
    v.getUnitVector()
    return v
  }
}

// 碰撞基类
class Crash{
  constructor() {

  }
  // 设置待检查的碰撞图形数据
  setCrashGraphics() {
    throw new Error('this function be inherit')
  }
  // 获取碰撞检测结果
  getCrashCheck() {
    throw new Error('this function be inherit')
  }
  // 判断所有法向量的投影长度是否有重叠
  checkShadowOverlap(list1, list2) {
    const f_max = queryMaxForArr(list1)
    const f_min = queryMinForArr(list1)
    const s_max = queryMaxForArr(list2)
    const s_min = queryMinForArr(list2)
    let is_overlap = false
    if (f_max > s_min && s_max > f_min) {
      is_overlap = true
    }
    return is_overlap
  }
}

// 坐标点与多边形的碰撞检测
class PointAndPolygonCrash extends Crash {
  constructor() {
    super()
    this.edge_vector_list = []
    this.point_shadow = []
    this.point = [0, 0]
    this.polygon_shadow = []
    this.polygon_point = [[0, 0]]
  }
  // 设置数据
  setCrashGraphics(point, polygon_point) {
    this.point = point
    this.polygon_point = polygon_point
    this.edge_vector_list = []
    this.getEdgeVector()
  }
  // 计算法向量
  getEdgeVector() {
    const polygon_length = this.polygon_point.length
    const v = new Vector([0, 0])
    const v2 = new Vector([0, 0])
    for (let i = 0; i < polygon_length; i++) {
      v.x = this.polygon_point[i][0]
      v.y = this.polygon_point[i][1]
      let next_index = 0
      if (i + 1 < polygon_length) {
        next_index = i + 1
      }
      v2.x = this.polygon_point[next_index][0]
      v2.y = this.polygon_point[next_index][1]
      this.edge_vector_list.push(v.substruct(v2).getUnitNormalVector())
    }
  }
  // 获取碰撞检测结果
  getCrashCheck() {
    const edge_length = this.edge_vector_list.length
    const v = new Vector([0, 0])
    for (let i = 0; i < edge_length; i++) {
      this.polygon_shadow = this.getEdgeShadowForVector(this.polygon_point, i, v)
      v.x = this.point[0]
      v.y = this.point[1]
      this.point_shadow = this.edge_vector_list[i].getShadowLength(v)
      const is_overlap = this.checkPointAndShadowOverlap()
      // 未发生碰撞就返回
      if (!is_overlap) {
        return false
      }
    }
    // 到这就碰撞了
    return true
  }
  // 计算获取结果
  getEdgeShadowForVector(list, edge_index, v) {
    const list_length = list.length
    const shadow_list = []
    for (let i = 0; i < list_length; i++) {
      v.x = list[i][0]
      v.y = list[i][1]
      shadow_list.push(this.edge_vector_list[edge_index].getShadowLength(v))
    }
    return shadow_list
  }
  // 判断坐标点是否和投影重叠
  checkPointAndShadowOverlap() {
    const s_max = queryMaxForArr(this.polygon_shadow)
    const s_min = queryMinForArr(this.polygon_shadow)
    let is_overlap = false
    if (s_max > this.point_shadow && this.point_shadow > s_min) {
      is_overlap = true
    }
    return is_overlap
  }
}

// 定义圆形与多边形碰撞
class RoundAndRectCrash extends PointAndPolygonCrash{
  constructor() {
    super()
    this.edge_vector_list = []
    this.round_center_point = []
    this.round_radius = 0
    this.round_shadow = []
    this.polygon_point = [[0, 0]]
    this.polygon_shadow = []
  }
  // 设置图形数据，设置圆的圆心与半径
  setCrashGraphics(round_center, round_radius, rect_point) {
    this.round_center_point = round_center
    this.round_radius = round_radius
    this.polygon_point = rect_point
    this.edge_vector_list = []
    this.getEdgeVector()
  }
  // 获取碰撞检测结果
  getCrashCheck() {
    const edge_length = this.edge_vector_list.length
    const v = new Vector([0, 0])
    for (let i = 0; i < edge_length; i++) {
      this.polygon_shadow = this.getEdgeShadowForVector(this.polygon_point, i, v)
      this.round_shadow = this.getRoundPointAndRadius(i, v)
      const is_overlap = this.checkShadowOverlap(this.polygon_shadow, this.round_shadow)
      // 未发生碰撞就返回
      if (!is_overlap) {
        return false
      }
    }
    // 到这就碰撞了
    return true
  }
  // 计算圆心与最近的一个点的向量
  getRoundPointAndRadius(edge_index, v) {
    const round_shadow = []
    const edge_v = this.edge_vector_list[edge_index]
    const rotate = Math.atan2(edge_v.y, edge_v.x)
    v.x = this.round_center_point[0] + Number((Math.cos(rotate) * this.round_radius).toFixed(2))
    v.y = this.round_center_point[1] + Number((Math.sin(rotate) * this.round_radius).toFixed(2))
    round_shadow.push(this.edge_vector_list[edge_index].getShadowLength(v))
    v.x = this.round_center_point[0] - Number((Math.cos(rotate) * this.round_radius).toFixed(2))
    v.y = this.round_center_point[1] - Number((Math.sin(rotate) * this.round_radius).toFixed(2))
    round_shadow.push(this.edge_vector_list[edge_index].getShadowLength(v))
    return round_shadow
  }
}

// 定义计算两个凸多边形的碰撞检测类
class PolygonCrash extends PointAndPolygonCrash{
  constructor() {
    super()
    this.edge_vector_list = []
    this.first_polygon_point_list = []
    this.first_polygon_shadow = []
    this.second_polygon_point_list = []
    this.second_polygon_shadow = []
  }
  // 设置所有向量对应的法向量
  // 首先设置多边形的图形数据
  setCrashGraphics(f_point, s_point) {
    this.first_polygon_point_list = f_point
    this.second_polygon_point_list = s_point
    this.edge_vector_list = []
    this.setEdgeVector(this.first_polygon_point_list)
    this.setEdgeVector(this.second_polygon_point_list)
  }
  // 然后设置每两个左边点对应的向量的法向量
  setEdgeVector(list) {
    const list_length = list.length
    const v1 = new Vector([0, 0])
    const v2 = new Vector([0, 0])
    for (let i = 0; i < list_length; i++) {
      v1.x = list[i][0]
      v1.y = list[i][1]
      let next_index = 0
      if (i + 1 < list_length) {
        next_index = i + 1
      }
      v2.x = list[next_index][0]
      v2.y = list[next_index][1]
      this.edge_vector_list.push(v1.substruct(v2).getUnitNormalVector())
    }
  }
  // 获取碰撞检查,根据法向量计算所有向量在一个法向量上的投影长度
  getCrashCheck() {
    const edge_list_length = this.edge_vector_list.length
    const v = new Vector([0, 0])
    for (let edge_index = 0; edge_index < edge_list_length; edge_index++) {
      // 判断在这一个法向量上的投影长度
      this.first_polygon_shadow = this.getEdgeShadowForVector(this.first_polygon_point_list, edge_index, v)
      this.second_polygon_shadow = this.getEdgeShadowForVector(this.second_polygon_point_list, edge_index, v)
      const is_overlap = this.checkShadowOverlap(this.first_polygon_shadow, this.second_polygon_shadow)
      // 如果有一个法向量的投影没有重叠，则表示未碰撞
      if (!is_overlap) {
        return false
      }
    }
    // 前面的代码判断都没有返回，就说明碰撞了
    return true
  }

}
